/**
 *  JFTSTool - Java Full Text Search tool.
 *  Copyright (C) <2009>  <grupo JFTS>
 *  This program is free software: you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License as published by
 *	the Free Software Foundation, either version 3 of the License, or
 *	(at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.jftstool.fileParserFramework;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.MissingResourceException;

import org.jftstool.config.FileParserFrameworkConfig;
import org.jftstool.config.JFTSConfiguration;
import org.jftstool.config.exceptions.JFTSConfigException;
import org.jftstool.fileParserFramework.exceptions.DocumentHandlerException;
import org.jftstool.fileParserFramework.exceptions.FileHandlerException;
import org.jftstool.fileParserFramework.exceptions.LanguageDetectorException;
import org.jftstool.fileParserFramework.exceptions.MimeTypeException;
import org.jftstool.fileParserFramework.languajeDetector.LanguageDetector;
import org.jftstool.fileParserFramework.metadata.DocumentMetaData;
import org.jftstool.fileParserFramework.mimeType.MimeTypeHandler;
import org.xml.sax.ContentHandler;

/**
 * @author grupo JFTS
 *
 */
public class FileFormatHandler implements IFileHandler{
	private MimeTypeHandler mimeHandler = null;
	private LanguageDetector languageHandler = null;
	FileParserFrameworkConfig config = null;
	
	
	/**
	 * Default Constructor 
	 * @throws FileHandlerException
	 */
	public FileFormatHandler() throws FileHandlerException{
		try {
			mimeHandler = new MimeTypeHandler();
			languageHandler = LanguageDetector.getInstance();
			config = JFTSConfiguration.getInstance().getFPFConfig();
		}
		catch (LanguageDetectorException e) {
			throw new FileHandlerException(e.getMessage());
		}
		catch (JFTSConfigException e) {
			throw new FileHandlerException(e.getMessage());
		}
	}
	
	@Override
	public void getDocument(File file, ContentHandler resultHandler, DocumentMetaData metaData) throws FileHandlerException {
		IDocumentHandler handler = this.getHandlerClass(file);
		try {
			handler.getDocument(new FileInputStream(file), resultHandler, metaData);
			metaData.set(DocumentMetaData.CONTENT_TYPE, _getFileMimeType(file));
			metaData.set(DocumentMetaData.CONTENT_LANGUAGE, languageHandler.getLanguage(resultHandler.toString()));
			metaData.set(DocumentMetaData.URI, file.toURI().toString());
		}
		catch (FileNotFoundException e) {
			throw new FileHandlerException("File no't found: " + file.getAbsolutePath()); 
		}
		catch (DocumentHandlerException e) {
			throw new FileHandlerException(e.getMessage()); 
		}
		catch (MimeTypeException e) {
			throw new FileHandlerException(e.getMessage());			
		}
		catch (LanguageDetectorException e) {
			throw new FileHandlerException(e.getMessage());			
		}
	}
	
	/**
	 * Returns the parser for the type of file received as parameter.
	 * @param file
	 * @return
	 * @throws FileHandlerException
	 */
	private IDocumentHandler getHandlerClass(File file) throws FileHandlerException{
		IDocumentHandler handler = null;
		try {
			String fileExtension = this._getExtension(file.getName());
			
			String handlerClassName = config.getParserFromExtension(fileExtension);
			String  fileMimeType = _getFileMimeType(file);			
			
			if (fileMimeType == null){
				throw new FileHandlerException("MIME type no't supported: " + file.getAbsolutePath());
			}
			else{
				String mimeExtension = mimeHandler.getExtensionAssociatedToMimeType(fileMimeType.trim());
				if (mimeExtension != null && fileExtension.trim().equals(mimeExtension.trim())){
					Class<? extends IDocumentHandler> handlerClass = Class.forName(handlerClassName).asSubclass(IDocumentHandler.class);
					handler = (IDocumentHandler) handlerClass.newInstance();
				}
				else{
					if (mimeExtension != null){
						throw new FileHandlerException("MIME type no't associated to file extension. " + "MIME type: " + fileMimeType + ", Extension: " + fileExtension);
					}
					else{
						throw new FileHandlerException("MIME type no't associated to file extension. " + "MIME type: " + fileMimeType + ", Extension: " + mimeExtension);						
					}
				}
			}
		}
		catch (ClassNotFoundException e) {
			throw new FileHandlerException("Error to load handler class. Class not found");				
		}
		catch (InstantiationException e) {
			throw new FileHandlerException("Error to load handler class. Can't instantiate");			
		}
		catch (IllegalAccessException e) {
			throw new FileHandlerException("Error to load handler class. Illegal access");			
		}
		catch (MissingResourceException e) {
			throw new FileHandlerException("File extension isn't supported");			
		}
		catch (MimeTypeException e) {
			throw new FileHandlerException(e.getMessage());
		}		
		return handler;
	}
	

	/**
	 * Returns the parser class for the document according to the mime type of the same.
	 * @param mimeType
	 * @return
	 * @throws FileHandlerException
	 */
	private IDocumentHandler getHandlerClass(String mimeType) throws FileHandlerException{
		IDocumentHandler handler = null;
		try {
			String handlerClassName = config.getParserFromMimeType(mimeType);				
			if (handlerClassName != null){
				Class<? extends IDocumentHandler> handlerClass = Class.forName(handlerClassName).asSubclass(IDocumentHandler.class);
				handler = (IDocumentHandler) handlerClass.newInstance();
			}
			else{
				throw new FileHandlerException("Can't find the correct parser for the inputStream");						
			}
		}
		catch (ClassNotFoundException e) {
			throw new FileHandlerException("Error to load handler class. Class not found");				
		}
		catch (InstantiationException e) {
			throw new FileHandlerException("Error to load handler class. Can't instantiate");			
		}
		catch (IllegalAccessException e) {
			throw new FileHandlerException("Error to load handler class. Illegal access");			
		}
		return handler;
	}	
	
	
	/**
	 * Returns the file extension you receive as a parameter. 
	 * @param fileName
	 * @return
	 */
	private String _getExtension(String fileName){
		String extension = null;		
		if (fileName != null){
			int index = fileName.indexOf(".");
			if ((index > 0) && (index < fileName.length())) {
				extension = fileName.substring(index + 1, fileName.length());
			}			
		}
		return (extension == null) ? "" : extension.toLowerCase(); 
	}
	
	
	/**
	 * Returns the mime type for the document received as a parameter. 
	 * @param file
	 * @return
	 * @throws MimeTypeException
	 */
	private String _getFileMimeType(File file) throws MimeTypeException{
		return mimeHandler.getMimeType(file);
	}
	
	/**
	 * Returns the mime type for the document received as InputStream. 
	 * @param is
	 * @return
	 * @throws MimeTypeException
	 */
	private String _getFileMimeType(InputStream is) throws MimeTypeException{
		return mimeHandler.getMimeType(is);
	}
	

	@Override
	public void getDocument(InputStream is, ContentHandler resultHandler, DocumentMetaData metaData) throws FileHandlerException {
		try {		
			String  mimeType = _getFileMimeType(is);
			is.reset();
			if (mimeType != null){
				IDocumentHandler handler = this.getHandlerClass(mimeType);
				handler.getDocument(is, resultHandler, metaData);
				metaData.set(DocumentMetaData.CONTENT_TYPE, mimeType);
				metaData.set(DocumentMetaData.CONTENT_LANGUAGE, languageHandler.getLanguage(resultHandler.toString()));
			}
			else{
				throw new FileHandlerException("MIME type no't supported");			
			}			
		}
		catch (DocumentHandlerException e) {
			throw new FileHandlerException(e.getMessage()); 
		}
		catch (MimeTypeException e) {
			throw new FileHandlerException(e.getMessage());			
		}
		catch (LanguageDetectorException e) {
			throw new FileHandlerException(e.getMessage());			
		}
		catch (IOException e) {
			throw new FileHandlerException(e.getMessage());
		}
	}
}